package com.uuah.server.config.registry;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.collections.functors.InstanceofPredicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.api.lifecycle.IDisposable;
import com.uuah.api.lifecycle.IStoppable;
import com.uuah.api.lifecycle.Initialisable;
import com.uuah.exception.AbstractUuahException;
import com.uuah.exception.lifecycle.InitialisationException;
import com.uuah.server.UuahServer;
import com.uuah.server.api.IUuahContext;
import com.uuah.server.exception.registry.RegistrationException;
import com.uuah.utils.ClassUtils;
import com.uuah.utils.CollectionUtils;
import com.uuah.utils.StringUtils;

/**
 * @ThreadSafe Use synchronized(registry) when reading/writing/iterating over
 *             the contents of the registry hashmap.
 *
 *             <p>
 *             update record:updator，update time，update content and version
 *             </p>
 * @author <a href="jonny_quan@hotmail.com">jonny</a>
 * @date 2009 2009-3-27 上午10:03:43
 * @version 1.0.0
 */
public class TransientRegistry extends AbstractRegistry {
	protected transient final Logger logger = LoggerFactory
			.getLogger(TransientRegistry.class);
	public static final String REGISTRY_ID = "com.uuah.server.Registry.Transient";

	private Map<String, Object> registry = new HashMap<String, Object>();

	public TransientRegistry() {
		super(REGISTRY_ID);
		// synchronized (registry) {
		//
		// }
	}

	protected void doInitialise() throws InitialisationException {
		synchronized (registry) {
			Collection allObjects = lookupObjects(Object.class);
			Object obj;
			for (Iterator iterator = allObjects.iterator(); iterator.hasNext();) {
				obj = iterator.next();
				if (obj instanceof Initialisable) {
					((Initialisable) obj).initialise();
				}
			}
		}
	}

	// @Override
	protected void doDispose() {
		synchronized (registry) {
			Collection allObjects = lookupObjects(Object.class);
			Object obj;
			for (Iterator iterator = allObjects.iterator(); iterator.hasNext();) {
				obj = iterator.next();
				if (obj instanceof IDisposable) {
					((IDisposable) obj).dispose();
				}
			}
		}
	}

	public void registerObjects(Map objects) throws RegistrationException {
		if (objects == null) {
			return;
		}

		for (Iterator iterator = objects.entrySet().iterator(); iterator
				.hasNext();) {
			Map.Entry entry = (Map.Entry) iterator.next();
			registerObject(entry.getKey().toString(), entry.getValue());
		}
	}

	public Object lookupObject(String key) {
		synchronized (registry) {
			return registry.get(key);
		}
	}

	public Collection lookupObjects(Class returntype) {
		synchronized (registry) {
			return CollectionUtils.select(registry.values(),
					new InstanceofPredicate(returntype));
		}
	}

	public void registerObject(String key, Object value)
			throws RegistrationException {
		registerObject(key, value, Object.class);
	}

	public void registerObject(String key, Object object, Object metadata)
			throws RegistrationException {
		if (StringUtils.isBlank(key)) {
			throw new RegistrationException(
					"Attempt to register object with no key");
		}
		if (logger.isDebugEnabled()) {
			logger.debug("registering object:[" + object + "] - key:[" + key
					+ "] - metadata:[" + metadata + "]");
		}

		synchronized (registry) {
			if (registry.containsKey(key)) {
				logger
						.warn("TransientRegistry already contains an object named '"
								+ key
								+ "'.  The previous object will be overwritten.");
			}
			registry.put(key, object);
		}
		IUuahContext sc = UuahServer.getUuahContext();
		if (sc != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("applying lifecycle");
			}
			try {
				sc.getLifecycleManager().applyCompletedPhases(object);
			} catch (AbstractUuahException e) {
				throw new RegistrationException(e);
			}
		} else {
			throw new RegistrationException("Unable to register object (\""
					+ key + ":" + ClassUtils.getSimpleName(object.getClass())
					+ "\") because UuahContext has not yet been created.");
		}
	}

	public void unregisterObject(String key, Object metadata)
			throws RegistrationException {
		Object obj;
		synchronized (registry) {
			obj = registry.remove(key);
		}
		if (obj instanceof IStoppable) {
			try {
				((IStoppable) obj).stop();
			} catch (AbstractUuahException e) {
				throw new RegistrationException(e);
			}
		}
	}

	public void unregisterObject(String key) throws RegistrationException {
		unregisterObject(key, Object.class);
	}

	public boolean isReadOnly() {
		return false;
	}

	public boolean isRemote() {
		return false;
	}

}
